import socket
from selectors import DefaultSelector, EVENT_WRITE, EVENT_READ

selector = DefaultSelector()
stopped = False
urls_todo = {'/','/1','/2','/3','/4','/5','/6','/7','/8','/9'}

class Cramler:
    def __init__(self, url):
        self.url = url
        self.sock = None
        self.response = b''

    def fetch(self):
        self.sock = socket.socket()
        self.sock.setblocking(False)
        try:
            self.sock.connect(('example.com', 80))
        except BlockingIOError:
            pass
        #注册socket可写事件（EVENT_WRITE和发生后应该采取的回调函数
        selector.register(self.sock.fileno(), EVENT_WRITE, self.connected)

    def connected(self, key, mask):
        selector.unregister(key.fd)
        get = 'GET {0} HTTP/1.0\r\nHost: example.com\r\n\r\n'.format(self.url)
        self.sock.send(get.encode('ascii'))
        #注册socket可读事件(EVENT_READ)和发生后应该采取的回调函数
        selector.register(key.fd, EVENT_READ, self.read_response)



    def read_response(self, key, mask):
        global stopped
        #如果响应大于4kb，下一次循环会继续读
        chunk = self.sock.recv(4096)
        if chunk:
            self.response += chunk
        else:
            selector.unregister(key.fd)
            urls_todo.remove(self.url)
            if not urls_todo:
                stopped = True


def loop():
        while not stopped:
            #阻塞，直到一个事件发生,用stopped全局变量控制事件循环何时停止。当urls_todo消耗完毕后，会标记stopped为True。
            events = selector.select()
            for event_key, event_mask in events:
                callback = event_key.data
                callback(event_key, event_mask)


if __name__ == '__main__':
    import time
    start = time.time()
    for url in urls_todo:
        cramler = Cramler(url)
        cramler.fetch()
    loop()
    print(time.time() - start)
